#include <stdio.h>
#include <memory>
#include <iostream>

#include "deplibUV.h"
#include "UdpSocket.h"
#include "rtp/RtpPacket.h"
#include "rtp/NackGenerator.h"

static constexpr unsigned int SendNackDelay{ 0u }; // In ms.
static std::shared_ptr<Rtp::NackGenerator> nackGenerator;

class ListenerNack: public Rtp::NackGenerator::Listener {
public:
    ~ListenerNack() override = default;

    void OnNackGeneratorNackRequired(const std::vector<uint16_t>& seqNumbers) override {
        for (auto &seqNum : seqNumbers) {
            std::cout << "seq:" << seqNum << std::endl;
        }
    }
    
    void OnNackGeneratorKeyFrameRequired() override {
        std::cout << "OnNackGeneratorKeyFrameRequired" << std::endl;
    }
};

class ListenerImpl : public UdpSocket::Listener {
public:
    void OnUdpSocketPacketReceived(UdpSocket *socket, const uint8_t* data, size_t len,
                                   const struct sockaddr* addr) override {

        Rtp::RtpPacket* rtpPacket = Rtp::RtpPacket::Parse(data, len);
        if (!rtpPacket) {
            printf("Received non-RTP packet of length %zu from socket\n", len);
            return;
        }

        printf("Received packet of length %zu from socket\n", len);

        bool res = nackGenerator->ReceivePacket(rtpPacket, true);
        if (res) {
            std::cout << "receivePacket is true" << std::endl;
        } else {
            std::cout << "receivePacket is false" << std::endl;
        }

        delete rtpPacket;
    }
};

int main() {
    printf("Hello, World!\n");

    DepLibUV::ClassInit();


    std::unique_ptr<UdpSocket::Listener> listener = std::make_unique<ListenerImpl>();

    std::string ip = "0.0.0.0";

    SocketFlags flags;
    flags.ipv6Only = false; // Set to true if you want to bind to IPv6 only
    flags.udpReusePort = true; // Set to true if you want

    std::unique_ptr<UdpSocket> udpSocket = std::make_unique<UdpSocket>(listener.get(), ip, 34500, flags); 

    std::unique_ptr<ListenerNack> nackListener = std::make_unique<ListenerNack>();

    nackGenerator = std::make_shared<Rtp::NackGenerator>(nackListener.get(), SendNackDelay);

    DepLibUV::RunLoop();
    DepLibUV::ClassDestroy();
    
    return 0;
}